package util.shaders;

import general.CachedResource;
import javax.media.opengl.GL;
import com.sun.opengl.util.texture.Texture;
import util.BasicGraphicsJogl;

public class Program implements CachedResource
{
	private String vertexShaderResourceString;
	private String fragmentShaderResourceString;
	private Shader vertexShader;
	private Shader fragmentShader;
	private int programHandle;
	
	Program(String vertexShaderResourceString,String fragmentShaderResourceString)
	{
		this.vertexShaderResourceString = vertexShaderResourceString;
		this.fragmentShaderResourceString = fragmentShaderResourceString;
	}

	public void allocate()
	{
		BasicGraphicsJogl basicGraphics = BasicGraphicsJogl.instance();
		GL gl = basicGraphics.getGL();
		vertexShader = Shader.getAllocatedShader(GL.GL_VERTEX_SHADER,vertexShaderResourceString);
		fragmentShader = Shader.getAllocatedShader(GL.GL_FRAGMENT_SHADER,fragmentShaderResourceString);
		programHandle = gl.glCreateProgram();
		gl.glAttachObjectARB(programHandle, vertexShader.getHandle());
		gl.glAttachObjectARB(programHandle, fragmentShader.getHandle());
		
		gl.glLinkProgramARB(programHandle);
		basicGraphics.assertShaderStatus(programHandle,GL.GL_LINK_STATUS);
		gl.glValidateProgramARB(programHandle);
		basicGraphics.assertShaderStatus(programHandle,GL.GL_VALIDATE_STATUS);
	}
	@Override
	public void destroy()
	{
		BasicGraphicsJogl basicGraphics = BasicGraphicsJogl.instance();
		GL gl = basicGraphics.getGL();
		gl.glDeleteProgram(programHandle);
		vertexShader.release();
		fragmentShader.release();
	}
	
	@Override
	public int hashCode()
	{
		return vertexShaderResourceString.hashCode() * 31 + fragmentShaderResourceString.hashCode();
	}
	@Override
	public boolean equals(Object object)
	{
		Program program = (Program) object;
		return (vertexShaderResourceString.equals(program.vertexShaderResourceString)) &&
			   (fragmentShaderResourceString.equals(program.fragmentShaderResourceString));
	}
	public void set()
	{
		BasicGraphicsJogl basicGraphics = BasicGraphicsJogl.instance();
		GL gl = basicGraphics.getGL();
		gl.glUseProgramObjectARB(programHandle);
	}
	public int getAttributeLocation(String attributeName)
	{
		BasicGraphicsJogl basicGraphics = BasicGraphicsJogl.instance();
		GL gl = basicGraphics.getGL();
		return gl.glGetAttribLocationARB(programHandle, attributeName);
	}
	public int getUniformLocation(String attributeName)
	{
		BasicGraphicsJogl basicGraphics = BasicGraphicsJogl.instance();
		GL gl = basicGraphics.getGL();
		return gl.glGetUniformLocationARB(programHandle, attributeName);
	}
	public void setUniformFloat(String attributeName,float value)
	{
		BasicGraphicsJogl basicGraphics = BasicGraphicsJogl.instance();
		GL gl = basicGraphics.getGL();
		int attributeLocation = getUniformLocation(attributeName);
		gl.glUniform1fARB(attributeLocation, value);
	}
	public void setTexture(String textureName,Texture texture,int samplerIndex)
	{
		BasicGraphicsJogl basicGraphics = BasicGraphicsJogl.instance();
		GL gl = basicGraphics.getGL();
		int textureLocation = getUniformLocation(textureName);
		basicGraphics.bind(texture,samplerIndex);
		gl.glUniform1iARB(textureLocation, samplerIndex);
	}
}
